﻿#region - 版 本 注 释 -
/*----------------------------------------------------------------
 * 版权所有 (c) 2024   保留所有权利。
 * CLR版本：4.0.30319.42000
 * 机器名称：DESKTOP-GLJ2Q8J
 * 公司名称：
 * 命名空间：AutoCAD.EntityTool
 * 唯一标识：b893f674-d9d1-4fd6-88a5-6b43f5b1d8e0
 * 文件名：BlockTools
 * 当前用户域：DESKTOP-GLJ2Q8J
 * 
 * 创建者：Guo-79991
 * 电子邮箱：799919859@qq.com
 * 创建时间：2024/7/15 12:05:36
 * 版本：V1.0.0
 *
 * 功能描述(Description):
 * 参考文档(Reference):
 * 数据表(Tables):
 * 作者(Author):Guo
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/
#endregion - 版 本 注 释 -


namespace AutoCAD.EntityTools.Jig
{
    /// <summary>
    /// 建筑墙线Jig
    /// </summary>
    public class DoubleWallLineJig : EntityJig
    {
        private Point3d _startPoint;
        private Point3d _endPoint;
        private string _prompt;
        private string[] _keywords;
        private double _wallThickness;
        private short _wallColor;
        private List<Point3d> _wallPoints;

        /// <summary>
        /// 双线建筑墙线Jig构造函数
        /// </summary>
        public DoubleWallLineJig(Point3d startPoint, string prompt, string[] keywords,
                               double wallThickness = 200, short wallColor = 8,
                               List<Point3d> existingPoints = null)
            : base(new Line(startPoint, startPoint))
        {
            _startPoint = startPoint;
            _endPoint = startPoint;
            _prompt = prompt;
            _keywords = keywords;
            _wallThickness = wallThickness;
            _wallColor = wallColor;
            _wallPoints = existingPoints ?? new List<Point3d>();
            _wallPoints.Add(startPoint);
        }

        protected override SamplerStatus Sampler(JigPrompts prompts)
        {
            var jigOptions = new JigPromptPointOptions(_prompt)
            {
                UserInputControls = UserInputControls.Accept3dCoordinates |
                                   UserInputControls.NoNegativeResponseAccepted,
                AppendKeywordsToMessage = false,
                BasePoint = _startPoint,
                UseBasePoint = true
            };

            // 添加关键字
            if (_keywords != null && _keywords.Length > 0)
            {
                foreach (var keyword in _keywords)
                {
                    jigOptions.Keywords.Add(keyword);
                }
            }

            jigOptions.Keywords.Add("Close");
            jigOptions.Keywords.Add("Undo");
            jigOptions.Keywords.Add("Exit");

            var promptResult = prompts.AcquirePoint(jigOptions);

            if (promptResult.Status == PromptStatus.Cancel ||
                promptResult.Status == PromptStatus.Error)
                return SamplerStatus.Cancel;

            if (promptResult.Status == PromptStatus.Keyword)
                return SamplerStatus.OK;

            if (_endPoint.DistanceTo(promptResult.Value) < Tolerance.Global.EqualPoint)
                return SamplerStatus.NoChange;

            _endPoint = promptResult.Value;
            return SamplerStatus.OK;
        }

        protected override bool Update()
        {
            try
            {
                ((Line)Entity).EndPoint = _endPoint;
                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 获取创建的双线墙线
        /// </summary>
        public List<Entity> GetWallLines()
        {
            return CreateDoubleWallLines(_startPoint, _endPoint, _wallThickness, _wallColor);
        }

        /// <summary>
        /// 创建双线建筑墙线
        /// </summary>
        public static List<Entity> CreateDoubleWallLines(Point3d startPoint, Point3d endPoint,
                                                       double wallThickness = 200, short wallColor = 8)
        {
            var wallLines = new List<Entity>();

            if (startPoint.DistanceTo(endPoint) < 0.1)
                return wallLines;

            // 计算墙线方向向量
            Vector3d direction = endPoint - startPoint;
            if (direction.Length < 0.1)
                return wallLines;

            Vector3d perpendicular = direction.GetPerpendicularVector().GetNormal();

            // 计算偏移距离
            double offsetDistance = wallThickness / 2;

            // 创建两条墙线
            var wallLine1 = CreateOffsetLine(startPoint, endPoint, perpendicular * offsetDistance);
            var wallLine2 = CreateOffsetLine(startPoint, endPoint, perpendicular * -offsetDistance);

            wallLine1.ColorIndex = wallColor;
            wallLine2.ColorIndex = wallColor;

            wallLines.Add(wallLine1);
            wallLines.Add(wallLine2);

            return wallLines;
        }

        /// <summary>
        /// 创建偏移直线
        /// </summary>
        private static Line CreateOffsetLine(Point3d startPoint, Point3d endPoint, Vector3d offset)
        {
            return new Line(startPoint + offset, endPoint + offset);
        }

        /// <summary>
        /// 获取下一个起点
        /// </summary>
        public Point3d GetNextStartPoint()
        {
            return _endPoint;
        }

        /// <summary>
        /// 获取所有墙线点
        /// </summary>
        public List<Point3d> GetWallPoints()
        {
            return _wallPoints;
        }

        /// <summary>
        /// 添加点到最后
        /// </summary>
        public void AddPoint(Point3d point)
        {
            _wallPoints.Add(point);
        }

        /// <summary>
        /// 获取墙线长度
        /// </summary>
        public double GetWallLength()
        {
            return _startPoint.DistanceTo(_endPoint);
        }
    }

    public static class DoubleWallTools
    {
        /// <summary>
        /// 连续创建双线建筑墙线
        /// </summary>
        public static List<List<ObjectId>> CreateContinuousDoubleWalls(this Document document,
                                                                     double wallThickness = 200,
                                                                     short wallColor = 8)
        {
            var editor = document.Editor;
            var database = document.Database;
            var allWallGroups = new List<List<ObjectId>>();
            var wallPoints = new List<Point3d>();

            try
            {
                editor.WriteMessage("\n开始连续绘制双线建筑墙线...");
                editor.WriteMessage("\n操作说明:");
                editor.WriteMessage("\n- 指定各个墙线转折点");
                editor.WriteMessage("\n- C: 闭合墙线");
                editor.WriteMessage("\n- U: 放弃上一段");
                editor.WriteMessage("\n- X: 结束绘制");

                // 获取起始点
                var startPointResult = editor.GetPoint("指定墙线起点:");
                if (startPointResult.Status != PromptStatus.OK)
                    return allWallGroups;

                Point3d currentStartPoint = startPointResult.Value;
                wallPoints.Add(currentStartPoint);

                bool continueDrawing = true;
                int segmentCount = 0;

                while (continueDrawing)
                {
                    segmentCount++;

                    // 创建Jig
                    var wallJig = new DoubleWallLineJig(currentStartPoint,
                                                      $"\n指定第 {segmentCount + 1} 点或 [闭合(C)/放弃(U)/结束(X)]:",
                                                      new[] { "C", "U", "X" },
                                                      wallThickness, wallColor,
                                                      wallPoints);

                    var dragResult = editor.Drag(wallJig);

                    switch (dragResult.Status)
                    {
                        case PromptStatus.OK:
                            var wallLines = wallJig.GetWallLines();
                            var wallLineIds = AddWallLinesToDatabase(wallLines, database);
                            allWallGroups.Add(wallLineIds);

                            currentStartPoint = wallJig.GetNextStartPoint();
                            wallPoints.Add(currentStartPoint);

                            editor.WriteMessage($"\n第 {segmentCount} 段墙线创建成功! 长度: {wallJig.GetWallLength():F2}mm");
                            break;

                        case PromptStatus.Keyword:
                            switch (dragResult.StringResult)
                            {
                                case "C": // 闭合
                                    if (wallPoints.Count >= 3)
                                    {
                                        // 创建闭合段
                                        var closeLines = DoubleWallLineJig.CreateDoubleWallLines(
                                            currentStartPoint, wallPoints[0], wallThickness, wallColor);

                                        var closeLineIds = AddWallLinesToDatabase(closeLines, database);
                                        allWallGroups.Add(closeLineIds);

                                        // 自动裁剪交叉部分
                                        TrimIntersectingWalls(allWallGroups, database);

                                        editor.WriteMessage("\n墙线已闭合并自动裁剪!");
                                    }
                                    else
                                    {
                                        editor.WriteMessage("\n需要至少3个点才能闭合!");
                                    }
                                    continueDrawing = false;
                                    break;

                                case "U": // 放弃上一段
                                    if (allWallGroups.Count > 0 && wallPoints.Count > 1)
                                    {
                                        var lastGroup = allWallGroups[allWallGroups.Count - 1];
                                        foreach (var id in lastGroup)
                                        {
                                            id.EraseEntity();
                                        }
                                        allWallGroups.RemoveAt(allWallGroups.Count - 1);
                                        wallPoints.RemoveAt(wallPoints.Count - 1);
                                        currentStartPoint = wallPoints[wallPoints.Count - 1];

                                        editor.WriteMessage("\n已放弃上一段墙线");
                                    }
                                    else
                                    {
                                        editor.WriteMessage("\n没有可放弃的墙线");
                                    }
                                    break;

                                case "X": // 结束
                                    // 自动裁剪交叉部分
                                    if (allWallGroups.Count > 1)
                                    {
                                        TrimIntersectingWalls(allWallGroups, database);
                                        editor.WriteMessage("\n墙线已自动裁剪!");
                                    }
                                    continueDrawing = false;
                                    editor.WriteMessage("\n结束墙线绘制");
                                    break;
                            }
                            break;

                        case PromptStatus.Cancel:
                            continueDrawing = false;
                            break;
                    }
                }

                editor.WriteMessage($"\n完成! 共创建 {allWallGroups.Count} 段墙线，{allWallGroups.Sum(g => g.Count)} 条线");
                return allWallGroups;
            }
            catch (Exception ex)
            {
                editor.WriteMessage($"\n错误: {ex.Message}");
                CleanupWallLines(allWallGroups);
                return new List<List<ObjectId>>();
            }
        }

        /// <summary>
        /// 添加墙线到数据库
        /// </summary>
        private static List<ObjectId> AddWallLinesToDatabase(List<Entity> wallLines, Database database)
        {
            var objectIds = new List<ObjectId>();

            using (var trans = database.TransactionManager.StartTransaction())
            {
                var bt = (BlockTable)trans.GetObject(database.BlockTableId, OpenMode.ForRead);
                var btr = (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);

                foreach (var wallLine in wallLines)
                {
                    btr.AppendEntity(wallLine);
                    trans.AddNewlyCreatedDBObject(wallLine, true);
                    objectIds.Add(wallLine.ObjectId);
                }

                trans.Commit();
            }

            return objectIds;
        }

        /// <summary>
        /// 裁剪交叉的墙线
        /// </summary>
        private static void TrimIntersectingWalls(List<List<ObjectId>> allWallGroups, Database database)
        {
            try
            {
                using (var trans = database.TransactionManager.StartTransaction())
                {
                    // 收集所有墙线
                    var allLines = new List<Line>();
                    foreach (var group in allWallGroups)
                    {
                        foreach (var id in group)
                        {
                            var line = trans.GetObject(id, OpenMode.ForWrite) as Line;
                            if (line != null) allLines.Add(line);
                        }
                    }

                    // 裁剪交叉点
                    for (int i = 0; i < allLines.Count; i++)
                    {
                        for (int j = i + 1; j < allLines.Count; j++)
                        {
                            TrimIntersection(allLines[i], allLines[j]);
                        }
                    }

                    // 清理重复的短线
                    CleanupShortLines(allLines);

                    trans.Commit();
                }
            }
            catch
            {
                // 裁剪失败不影响主要功能
            }
        }

        /// <summary>
        /// 裁剪两条线的交叉点
        /// </summary>
        private static void TrimIntersection(Line line1, Line line2)
        {
            try
            {
                // 计算交点
                Point3dCollection intersections = new Point3dCollection();
                line1.IntersectWith(line2, Intersect.OnBothOperands, intersections, IntPtr.Zero, IntPtr.Zero);

                if (intersections.Count > 0)
                {
                    Point3d intersection = intersections[0];

                    // 只裁剪距离交点较近的端点
                    TrimLineEnd(line1, intersection);
                    TrimLineEnd(line2, intersection);
                }
            }
            catch
            {
                // 忽略裁剪错误
            }
        }

        /// <summary>
        /// 裁剪线的端点
        /// </summary>
        private static void TrimLineEnd(Line line, Point3d intersection)
        {
            double distToStart = line.StartPoint.DistanceTo(intersection);
            double distToEnd = line.EndPoint.DistanceTo(intersection);

            if (distToStart < distToEnd && distToStart > 0.1)
            {
                line.StartPoint = intersection;
            }
            else if (distToEnd > 0.1)
            {
                line.EndPoint = intersection;
            }
        }

        /// <summary>
        /// 清理过短的线
        /// </summary>
        private static void CleanupShortLines(List<Line> lines)
        {
            for (int i = lines.Count - 1; i >= 0; i--)
            {
                if (lines[i].Length < 1.0) // 小于1单位的线认为是无效的
                {
                    try
                    {
                        lines[i].Erase();
                        lines.RemoveAt(i);
                    }
                    catch
                    {
                        // 忽略清理错误
                    }
                }
            }
        }

        /// <summary>
        /// 清理墙线
        /// </summary>
        private static void CleanupWallLines(List<List<ObjectId>> allWallGroups)
        {
            foreach (var group in allWallGroups)
            {
                foreach (var id in group)
                {
                    try { id.EraseEntity(); } catch { }
                }
            }
        }

        /// <summary>
        /// 创建单段双线建筑墙线
        /// </summary>
        public static List<ObjectId> CreateSingleDoubleWall(this Document document,
                                                          double wallThickness = 200,
                                                          short wallColor = 8)
        {
            var editor = document.Editor;
            var database = document.Database;

            try
            {
                // 获取起点
                var startOptions = new PromptPointOptions("指定墙线起点:");
                var startResult = editor.GetPoint(startOptions);
                if (startResult.Status != PromptStatus.OK)
                    return new List<ObjectId>();

                var startPoint = startResult.Value;

                // 获取终点
                var endOptions = new PromptPointOptions("\n指定墙线终点:")
                {
                    UseBasePoint = true,
                    BasePoint = startPoint
                };
                var endResult = editor.GetPoint(endOptions);
                if (endResult.Status != PromptStatus.OK)
                    return new List<ObjectId>();

                var endPoint = endResult.Value;

                // 创建墙线
                var wallLines = DoubleWallLineJig.CreateDoubleWallLines(startPoint, endPoint, wallThickness, wallColor);

                return AddWallLinesToDatabase(wallLines, database);
            }
            catch (Exception ex)
            {
                editor.WriteMessage($"\n错误: {ex.Message}");
                return new List<ObjectId>();
            }
        }

        /// <summary>
        /// 从现有直线创建双线墙
        /// </summary>
        public static List<ObjectId> CreateDoubleWallFromLine(this Document document, ObjectId lineId,
                                                            double wallThickness = 200, short wallColor = 8)
        {
            var wallLineIds = new List<ObjectId>();
            var database = document.Database;

            try
            {
                using (Transaction trans = database.TransactionManager.StartTransaction())
                {
                    var line = trans.GetObject(lineId, OpenMode.ForRead) as Line;
                    if (line == null)
                    {
                        document.Editor.WriteMessage("\n错误: 选择的对象不是直线");
                        return wallLineIds;
                    }

                    var wallLines = DoubleWallLineJig.CreateDoubleWallLines(
                        line.StartPoint, line.EndPoint, wallThickness, wallColor);

                    wallLineIds = AddWallLinesToDatabase(wallLines, database);

                    trans.Commit();
                }

                document.Editor.WriteMessage($"\n从直线创建了 {wallLineIds.Count} 条墙线");
                return wallLineIds;
            }
            catch (Exception ex)
            {
                document.Editor.WriteMessage($"\n错误: {ex.Message}");
                return wallLineIds;
            }
        }
    }



}